-- An object of this class handles the Experience and Level aspect of an Engine in the view of the game.
-- [since all this goes into/ belongs to "OOExpEngine.lua", I guess we might name that as this and merge]

include("LuaRules/Classes/OOLuaClass.lua")

local bases, engines, unitCounts, squadSize = include("LuaRules/Configs/Engine_defs.lua")
local abilityTable,rampageDesc,jumpDesc,upRampageLvl,upJumpLvl,empDesc,upEmpLvl,repairDesc,upRepairLvl = include("LuaRules/Configs/Ability_defs.lua")

-- -- This is no gadget but a class file which handle the level of
-- the engines. It also sets the values of the unit which is assosiated to the engine.

--------------------------------
---- Config vars (more or less)

--defines lvlups of Engines

local CMD_UPABILITYONE = 33330
local CMD_UPABILITYTWO = 33331

local LevelHandlerLvlup ={
			[1] = 2,
			[2] = 6,
			[3] = 12,
			[4] = 24,
			[5] = 38,		-- just some numbers for now - could be used for cumulative, or that many each level
			[6] = 54,
			[7] = 78,
			[8] = 128,
			[9] = 256,
			[10] = 12345678, -- catchall - am lazy
			}

local hpincreaseFactor = 1.2		-- instead of this, we probably want to make a number of generic values (think stregth, intelligence, etc)
local AttackSpeedChange = 0.9		-- that then take influence on the basic values according to formula
local damageIncreaseFactor = 1.2	-- this has the large benefit that we don't need engine specific sections below (ie SetKnightValues, etc.)
									-- but can instead use config values to similiar/same effect
------------------------------------------
			
-- Class proper
			
LevelHandler = {}					-- hmm, probably need to think about interactions with items/equipment as well...

local LevelHandler_mt = Class(LevelHandler)	


--Constructor
function LevelHandler:new(unitID,unitDefID,teamID)	-- want the EngineID here (ie what we're going to use as unique ID - could probably go with teamID for now... or just keep all three, MetaEngine can pass on)
  self:SetUnitValues(unitID,unitDefID,0)	-- will that work like so ? perhaps after table has been returned? or even not then ?
  Spring.Echo(abilityTable[unitDefID].abilityOne)
  
  local localAbilityTable = abilityTable[unitDefID]	-- is setting it within the return broken/ doesn't work? so do here then...
  localAbilityTable.upabOne.id = CMD_UPABILITYONE
  localAbilityTable.upabTwo.id = CMD_UPABILITYTWO
  return setmetatable( 	{--declare member variables at this place:
  					 	currentLevel=0,
  					 	currentXP=0,
  					 	abilityLvLs = {[0] = 0, [1] = 0},	-- load from config, or tell to set from outside (for non 0 - 0, other tables). Probably load from config here
								-- use what as table index values? count from one, or use the CMDIDs ?
						abilityTable = localAbilityTable, -- ( Alfred starts at 0, me at 1...)
							--ideally, this would be a table with variable length - do that later though, else too many changes at once
  					 	lvlUpElementsShown = false,
  					 	abilityButtonsShown = {[0] = false, [1] = false},	-- this would depend on abilityLvls
  					 	}, LevelHandler_mt)
end
--- ooh, of course, I don't need to have these member variables queryable at the MetaEngine level - they're only ever queried through functions, which route to the ones here! yaaay..
-- so the ones I need from above or the only thing. For that, I guess do as described below

-- we have to also handle vars being asked upwards - ie we need unitID, teamID and such, but don't get it for "self.unitID" anymore...
-- could of course just pass them on down continously - ie each time we need them, require them as argument to the function. Probably easiest way to solve for now.

function LevelHandler:Respawn(unitID,unitDefID,teamID)
  self:SetUnitValues(unitID,unitDefID,self.currentLevel)
  
  local i = 0
  for _,buttonShown in pairs(self.abilityButtonsShown) do		-- aaahh - if I'd call this as if it were just a function to use, then the "self." would refer to the OOMetaEngine class, rather than to the lvlHandler object!
  	if (buttonShown) then
	  	self:AddAbilityButton(unitID,unitDefID,teamID,i)
	end
  	i = i + 1
  end
  
  if (self.lvlUpElementsShown) then
     self:AddGuiLvlUpElements(unitID,unitDefID,teamID)
  end
  
end


function LevelHandler:GetCurrentLevel()
	return self.currentLevel
end

function LevelHandler:GetCurrentXP()
	return self.currentXP
end

function LevelHandler:AddXP(xpToAdd,unitID,unitDefID,teamID)
	self.currentXP = self.currentXP + xpToAdd

	--check for right level with current XP
	local rightLvl = 1
	while (LevelHandlerLvlup[rightLvl]<=self.currentXP) do
		rightLvl = rightLvl + 1
		if (LevelHandlerLvlup[rightLvl]==nil) then
			return nil
		end
	end -- ok, this is a nice solution :)

	--level up if current level lower than right level
	if (self.currentLevel < rightLvl) then --lvlUP
		Spring.Echo("New LevelHandler: Lvl up!")
		self.currentLevel = rightLvl
		self:SetUnitValues(unitID,unitDefID,self.currentLevel)
		if (not self.lvlUpElementsShown) then
			self:AddGuiLvlUpElements(unitID,unitDefID,teamID)
			self.lvlUpElementsShown = true
		end
	end
end

function LevelHandler:OpenLevelUps()
	local abilityLvls = 0
	for abilityID,abilityLvl in pairs(self.abilityLvLs) do	
		abilityLvls = abilityLvls + abilityLvl
	end
	return (self.currentLevel - abilityLvls)
end												

function LevelHandler:GetAbilityLvl(abilityID)
	-- Spring.Echo(self.abilityLvLs[abilityID])
	-- Spring.Echo("That was apparent ability level passed back")
	return self.abilityLvLs[abilityID]
end

function LevelHandler:AddAbilityLvl(abilityID,unitID,unitDefID,teamID)
	if (self:OpenLevelUps()>0) then
		self.abilityLvLs[abilityID] = self.abilityLvLs[abilityID] + 1
		if (self.abilityButtonsShown[abilityID] == false) then	-- so what's not working is the querying
			self.abilityButtonsShown[abilityID] = true
		
			--we have to first remove the level up buttons then add the ability button and then add the level up buttons again
			--because we can only remove the buttons which were added last. And the level up buttons have to be removed sooner
			--or later. (What a shit, we need another gui!)
			
			-- okay, that sounds bad :/. The problem is that I had thought we would use the commandsinserts even when we don't use them as Gui elements 
			-- - as they're convenient for unsynced to synced "communication" 
			-- (ie a widget or gadget checks for mouse clicks, and then gives the "order" to lvlup (which we catch with CommandFallBack) )
			-- I guess we could do it differently though (ie with SendLuaRulesMsg - though that is akward in some ways as well - see Keyboard-steering gadget)
			-- hmm - can we have widgets give orders even if there is no such CommandDesc ? then problem solved :D
			self:RemoveGuiLvlUpElements(unitID,unitDefID,teamID)	
			self:AddAbilityButton(unitID,unitDefID,teamID,abilityID) 
			self:AddGuiLvlUpElements(unitID,unitDefID,teamID)	
			
		end
	end
	
	if (self:OpenLevelUps()<=0) then
		if (self.lvlUpElementsShown) then	
			self:RemoveGuiLvlUpElements(unitID,unitDefID,teamID)	-- durr...
			self.lvlUpElementsShown = false
		end
	end
end

-----------------------------------------
---------These functions are only called from within the class - ie helper functions (hmm, are they?) if yes, we could make them local functions ???
------------------------------------------

function LevelHandler:SetUnitValues(unitID,unitDefID,level)		-- set various values according to the Engines level

	local newHP = UnitDefs[UnitDefNames.knight.id].health*hpincreaseFactor^(level) -- shouldn't be checking against knight for all engines...
	local proportionalHealth = Spring.GetUnitHealth(unitID)*hpincreaseFactor^(level) -- need to look into this - has been playing up in the past (ie increasing the proportional level of current HP at level up)

	Spring.SetUnitMaxHealth(unitID, newHP)
	Spring.SetUnitHealth(unitID, proportionalHealth)

	--make engine specific changes
	if (unitDefID == UnitDefNames.knight.id) then
		LevelHandler:SetKnightValues(unitID,level)
	elseif (unitDefID == UnitDefNames.rook.id) then
		LevelHandler:SetRookValues(unitID,level)
	elseif (unitDefID == UnitDefNames.queen.id) then
		LevelHandler:SetQueenValues(unitID,level)
	elseif (unitDefID == UnitDefNames.bishop.id) then
		LevelHandler:SetBishopValues(unitID,level)
	end
end

-- ah, these all unused at the moment - and likely to stay that way, if we can go for a value-set based (Strength, intelligence, etc.) stat improvement system
function LevelHandler:SetKnightValues(unitID,level)

end

function LevelHandler:SetRookValues(unitID,level)

end

function LevelHandler:SetQueenValues(unitID,level)

end

function LevelHandler:SetBishopValues(unitID,level)

end

--inserts buttons at level up	-- hurr ? always added ? where did the check use to be then ?
function LevelHandler:AddGuiLvlUpElements(unitID,unitDefID,_)	-- do we need to bother with asking for teamID ?
	Spring.InsertUnitCmdDesc(unitID,self.abilityTable.upabOne)	-- need to readd checks to not insert LvlUpCmds when that ability is alread maxed out. Or not ?
	Spring.InsertUnitCmdDesc(unitID,self.abilityTable.upabTwo)
end

function LevelHandler:RemoveGuiLvlUpElements(unitID,_,_)
	Spring.RemoveUnitCmdDesc(unitID,self.abilityTable.upabOne)	-- no errors if there's nothing to remove, I guess ?
	Spring.RemoveUnitCmdDesc(unitID,self.abilityTable.upabTwo)
end


function LevelHandler:AddAbilityButton(unitID,unitDefID,teamID,abilityID)
	if (abilityID==0) then
		Spring.InsertUnitCmdDesc(unitID,self.abilityTable.abilityOne)
	elseif (abilityID==1) then
		Spring.InsertUnitCmdDesc(unitID,self.abilityTable.abilityTwo)
	else
		Spring.Echo("Error in AddAbilityButton")
	end
end